package cn.mjnxin.iot.gate.connector;

import java.util.concurrent.TimeUnit;

import cn.mjnxin.iot.base.cache.ProtocalStrategyCache;
import cn.mjnxin.iot.base.domain.ProtocolConfig;
import cn.mjnxin.iot.base.log.LogWorker;
import cn.mjnxin.iot.base.util.CommonUtil;
import cn.mjnxin.iot.gate.coder.Gate2TerminalEncoder;
import cn.mjnxin.iot.gate.coder.Terminal2GateDecoder;
import cn.mjnxin.iot.gate.handle.GateAsServer4TerminalInHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * 网关获取终端报文
 * 
 * @author CLG 2023年10月10日
 * @version V1.0.0
 */
public class GateAsServer4Terminal {
    /**
     * 协议编号作为协议服务以及协议策略的唯一标识
     */
    private Integer pid;
    private Integer serverPort;
    private EventLoopGroup boss = new NioEventLoopGroup(1);
    private EventLoopGroup work = new NioEventLoopGroup(2);
	private int heartbeat = 30;

    public GateAsServer4Terminal(Integer pid, Integer serverPort, int heartbeat) {
        this.pid = pid;
        this.serverPort = serverPort;
        this.heartbeat = heartbeat;
    }

    /**
     * 对接Terminal 通过引导配置参数--长度域固定
     * 
     * @return
     */
    public ServerBootstrap config(ProtocolConfig protocolConfig) {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(boss, work)
        	.channel(NioServerSocketChannel.class)
//            .option(ChannelOption.SO_KEEPALIVE, true)
//            .option(ChannelOption.TCP_NODELAY, true)
            .option(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT)
            .childOption(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT)
            .childOption(ChannelOption.SO_KEEPALIVE, true)
            .childOption(ChannelOption.TCP_NODELAY, true)
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel sc) throws Exception {
                    // 心跳检测,超时时间xx秒，指定时间中没有读写操作会触发IdleStateEvent事件
                    sc.pipeline().addLast(new IdleStateHandler(heartbeat, -1, -1, TimeUnit.SECONDS));
                    // 自定义编解码器 需要在自定义的handler的前面即pipeline链的前端,不能放在自定义handler后面，否则不起作用
                    sc.pipeline().addLast("decoder", new Terminal2GateDecoder(protocolConfig));
                    sc.pipeline().addLast("encoder", new Gate2TerminalEncoder(protocolConfig.getLogLevel(), protocolConfig.getTerminalRepacker()));
                    sc.pipeline().addLast(new GateAsServer4TerminalInHandler(pid, protocolConfig.getLogLevel(), protocolConfig.getTerminalRepacker()));
                }
            });

        return serverBootstrap;
    }

    /**
     * 绑定服务到指定端口
     * 
     * @param serverBootstrap
     */
    public void bindAddress(ServerBootstrap serverBootstrap) {
        ChannelFuture channelFuture = null;;
        try {
            ProtocalStrategyCache.protocalServerCache.put(pid, this);
            channelFuture = serverBootstrap.bind(serverPort).sync();
            LogWorker.logForce(String.format("网关报文协议服务端%d:%d已启动YY", pid, serverPort));
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            LogWorker.error(e.getMessage(), e);
        } finally {
        	close();
        	if (channelFuture != null) {
                channelFuture.channel().close();
        	}
        }
    }

    /**
     * 关闭服务
     */
    public void close() {
        CommonUtil.closeEventLoop(boss, work);
        // 删除缓存中对应网关协议服务
        ProtocalStrategyCache.protocalServerCache.remove(pid);
    }
}
